
package com.joysuch.wwyt.dataperm.processor;

import java.util.List;

import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.dataperm.context.DataPermContextHolder;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.AllColumns;
import net.sf.jsqlparser.statement.select.AllTableColumns;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SelectVisitor;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.select.WithItem;
import net.sf.jsqlparser.statement.values.ValuesStatement;
import org.apache.commons.lang3.builder.ToStringBuilder;

public class DataPermissionProcessorBySqlParser2 {

    public String process(String sql) throws JSQLParserException {
        // 未启用数据权限，直接返回
        if (!DataPermContextHolder.isDataPermEnabled()) {
            return sql;
        }
        if (sql.startsWith("{")) {
            return sql;
        }
        Statement parse = CCJSqlParserUtil.parse(sql);
        if (parse instanceof Select) {
            long start = System.currentTimeMillis();
            if (((Select) parse).getSelectBody() instanceof PlainSelect) {
                sql = parsePlainSelect(parse);
            } else if (((Select) parse).getSelectBody() instanceof SetOperationList) {
                SetOperationList list = (SetOperationList) ((Select) parse).getSelectBody();
            }
            long end = System.currentTimeMillis();
            // System.out.println(((end - start) + "ms ") + sql);
            return sql;
        }
        return sql;
    }

    protected String parsePlainSelect(Statement parse) {
        PlainSelect plainSelect = (PlainSelect) ((Select) parse).getSelectBody();

        // 原where表达式
        Expression where = plainSelect.getWhere();
        List<Join> joins = plainSelect.getJoins();

        Expression condition = createExpressionForTable(plainSelect.getFromItem().getAlias());
        // System.out.println(condition);
        if (joins != null) {
            // System.out.println("joins:" + joins);
            // System.out.println(plainSelect.getFromItem().getAlias());
            for (Join j : joins) {
                if (j.isLeft() && j.isOuter()) {
                    // left outer join
                } else {
                    // System.out.println(j.getRightItem().getAlias());
                    condition = new AndExpression(condition, createExpressionForTable(j.getRightItem().getAlias()));
                }
            }
        }
        if (where == null) {
            where = condition;
        } else {
            where = new AndExpression(condition, where);
        }

        // 设置新的where条件
        plainSelect.setWhere(where);
        String sql = plainSelect.toString();
        return sql;
    }

    protected String processPlainSelect(PlainSelect plainSelect) {

        // 原where表达式
        Expression where = plainSelect.getWhere();

        List<Join> joins = plainSelect.getJoins();

        // if (shouldIntercept(plainSelect.getFromItem())) {
        // // 需要拦截
        //
        // }

        Expression condition = createExpressionForTable(plainSelect.getFromItem().getAlias());
        if (joins != null) {
            // System.out.println("joins:" + joins);
            // System.out.println(plainSelect.getFromItem().getAlias());
            for (Join j : joins) {
                condition = new AndExpression(condition, createExpressionForTable(j.getRightItem().getAlias()));

            }
        }
        if (where == null) {
            where = condition;
        } else {
            where = new AndExpression(condition, where);
        }

        // 设置新的where条件
        plainSelect.setWhere(where);
        String sql = plainSelect.toString();
        return sql;
    }

    private Expression createExpressionForTable(Alias alias) {
        String tenantColumn = "TENENT_ID";
        String orgCodeColumn = "ORG_CODE";
        if (alias != null) {
            tenantColumn = alias.getName() + "." + tenantColumn;
            orgCodeColumn = alias.getName() + "." + orgCodeColumn;
        }
        EqualsTo tenantId = new EqualsTo();
        tenantId.setLeftExpression(new Column(tenantColumn));
        tenantId.setRightExpression(new LongValue(Context.getCurrentTenantId()));

        LikeExpression code = new LikeExpression();
        code.setLeftExpression(new Column(orgCodeColumn));
        code.setRightExpression(new StringValue(Context.getCompanyCode() + "%"));
        return new AndExpression(tenantId, code);
    }

    public static void main(String[] args) {
        // String sql = "SELECT * FROM `wwyt_api_mh_monitor_point_data` AS a left join wwyt_api_test b on a.test_id =
        // b.id WHERE a.tag_name IN (SELECT b.point_code FROM `wwyt_mh_platform_point` AS b WHERE "
        // + "b.delete_flag ='0' AND b.switch_state = 1 AND b.platform_id =?1 AND a.tag_name = b.point_code) AND
        // a.tag_time BETWEEN ?2 AND ?3 and b.name = ?4";
        String sql = "select t1 from table1 t1 union all select t2.b,t3.c from table2 t2,table3 t3 where t2.b = t3.c and t2.c in (select id from app)";
        try {
            Statement parse = CCJSqlParserUtil.parse(sql);
            SelectBody body = ((Select) parse).getSelectBody();
            body.accept(new MySelectVisitor("root"));
            System.out.println(ToStringBuilder.reflectionToString(parse));
        } catch (JSQLParserException e) {
            e.printStackTrace();
        }
    }

    static class MySelectVisitor implements SelectVisitor {

        String prefix;

        public MySelectVisitor(String prefix) {
            this.prefix = prefix;
        }

        @Override
        public void visit(ValuesStatement aThis) {
            System.out.println(prefix + aThis);
            aThis.accept(new MySelectVisitor(this.prefix + "-> ValuesStatement: "));
            List<Expression> expressions = aThis.getExpressions();
        }

        @Override
        public void visit(WithItem withItem) {
            System.out.println(prefix + withItem);
            withItem.accept(new MySelectVisitor(this.prefix + "-> WithItem: "));
        }

        @Override
        public void visit(SetOperationList setOpList) {
            System.out.println(prefix + setOpList);
            List<SelectBody> selects = setOpList.getSelects();
            selects.forEach(e -> e.accept(new MySelectVisitor(this.prefix + "-> SetOperationList: ")));
            // setOpList.accept(new MySelectVisitor(this.prefix + "-> SetOperationList: "));
        }

        @Override
        public void visit(PlainSelect plainSelect) {
            System.out.println(prefix + plainSelect);
            if (plainSelect.getWhere() == null) {
                return;
            }
            plainSelect.getWhere().accept(new ExpressionVisitorAdapter() {

                @Override
                public void visit(AndExpression expr) {
                    super.visit(expr);
                    System.out.println("AndExpression: " + expr);
                }

                @Override
                public void visit(OrExpression expr) {
                    super.visit(expr);
                    System.out.println("OrExpression: " + expr);
                }

                @Override
                public void visit(SubSelect subSelect) {
                    super.visit(subSelect);

                    System.out.println("SubSelect: " + subSelect);
                }

                @Override
                public void visit(AllColumns allColumns) {
                    super.visit(allColumns);
                    System.out.println("AllColumns: " + allColumns);
                }

                @Override
                public void visit(AllTableColumns allTableColumns) {
                    super.visit(allTableColumns);
                    System.out.println("AllTableColumns: " + allTableColumns);
                }

            });
            // plainSelect.accept(new MySelectVisitor(this.prefix + "-> plainSelect: "));
        }
    }

}
